<template>
  <view :style="{ width: `${_width}rpx`, height: `${_height}rpx` }">
    <!-- #ifdef APP-NVUE -->
    <gcanvas
      v-if="show"
      :id="canvasId"
      :ref="canvasId"
      class="canvas"
      :style="{ width: `${_width}rpx`, height: `${_height}rpx` }"
    >
    </gcanvas>
    <!-- #endif -->
    <!-- #ifdef MP-WEIXIN || MP-ALIPAY || MP-QQ -->
    <canvas
      id="canvasId"
      type="2d"
      canvas-id="canvasId"
      class="canvas"
      :style="{ width: `${_width}rpx`, height: `${_height}rpx` }"
    ></canvas>
    <!-- #endif -->
    <!-- #ifndef MP-WEIXIN || MP-ALIPAY || MP-QQ || APP-NVUE -->
    <canvas
      :id="canvasId"
      :canvas-id="canvasId"
      class="canvas"
      :style="{ width: `${_width}rpx`, height: `${_height}rpx` }"
    ></canvas>
    <!-- #endif -->
  </view>
</template>

<script lang="ts" setup>
/**
 * 条形码
 * @description 这是一个条形码组件，属性多，可以生成非常个性化的组件哦~
 * 如果想知道生成的属性请查看：Baroptions类型属性。
 * 更改任意属性，都将会导致重绘
 */
import {
  getCurrentInstance,
  computed,
  ref,
  PropType,
  inject,
  ComponentInternalInstance,
  onMounted,
  nextTick,
  watch,
} from 'vue'
import CanvasRenderingContext2D from '../../tool/gcanvas/context-2d/RenderingContext.js'
import { drawBarCode, BarcodeObjType, Baroptions } from './drawing'
import { JsBarcode } from './jsbarcode/JsBarcode.js'
import JsBarcodeOptions from './jsbarcode/options/defaults.js'
// #ifdef APP-NVUE
import { enable, WeexBridge } from '../../tool/gcanvas/index.js'
// #endif
const proxy = getCurrentInstance()?.proxy ?? null

const props = defineProps({
  option: {
    type: Object as PropType<Baroptions>,
    default: () => {
      return JsBarcodeOptions
    },
  },
  width: {
    type: Number,
    default: 600,
  },
  height: {
    type: Number,
    default: 240,
  },
})
const vnodeCtx = proxy
const canvasId = ref('canvasId')
// #ifndef MP-WEIXIN || MP-ALIPAY || MP-QQ
canvasId.value = 'tm' + uni.$tm.u.getUid(5)
// #endif
let ctx: CanvasRenderingContext2D
let canvas2d: HTMLCanvasElement
let optsCode = computed(() => {
  let ops = { ...JsBarcodeOptions, ...props.option }
  ops.height = uni.upx2px(props.height) - 40
  return ops
})
const _width = computed(() => props.width)
const _height = computed(() => props.height)
const show = ref(false) //安卓上首次要隐藏不然卡。
onMounted(() => {
  nextTick(function () {
    // #ifdef APP-NVUE
    if (uni.getSystemInfoSync().osName == 'android') {
      setTimeout(function () {
        show.value = true
        init().then(() => draw())
      }, 200)
    } else {
      show.value = true
      init().then(() => draw())
    }
    // #endif
    // #ifndef APP-NVUE

    init().then(() => draw())
    // #endif
  })
})
function draw(opts = optsCode.value) {
  let bcode = JsBarcode(ctx, opts.text, opts)
  let BarcodeObj: BarcodeObjType = bcode._encodings[0][0]
  let is2d = canvas2d ? true : false

  drawBarCode(ctx, BarcodeObj.options, BarcodeObj, is2d, uni.upx2px(_width.value))
}
watch(
  () => props.option,
  () => {
    if (!ctx) {
      init().then(() => draw({ ...optsCode.value }))
    } else {
      draw({ ...optsCode.value })
    }
  },
  { deep: true }
)
function init() {
  return new Promise((res, rej) => {
    // #ifdef APP-NVUE
    setTimeout(async function () {
      ctx = await drawNvue_init()
      res(true)
    }, 100)
    // #endif
    // #ifdef MP-WEIXIN || MP-ALIPAY || MP-QQ
    setTimeout(async function () {
      const { ctx2d, canvas } = await MpWeix_init()
      ctx = ctx2d
      canvas2d = canvas
      res(true)
    }, 100)
    // #endif
    // #ifndef MP-WEIXIN || MP-ALIPAY || MP-QQ || APP-NVUE
    setTimeout(async function () {
      ctx = await appvueH5Other()
      res(true)
    }, 50)
    // #endif
  })
}
//appvue,h5,和其它平台。
function appvueH5Other() {
  return Promise.resolve(uni.createCanvasContext(canvasId.value, vnodeCtx))
}
//支付宝和微信，QQ 支持2d渲染。
function MpWeix_init(): Promise<{
  ctx2d: CanvasRenderingContext2D
  canvas: HTMLCanvasElement
}> {
  return new Promise((resolve, rej) => {
    const query = uni.createSelectorQuery().in(vnodeCtx)

    // #ifdef MP-ALIPAY
    query
      .select('#canvasId')
      .node()
      .exec((res2) => {
        const canvas = res2[0].node
        let ctxvb: UniApp.CanvasContext = canvas.getContext('2d')
        resolve({ ctx2d: ctxvb, canvas: canvas })
      })
    // #endif
    // #ifdef MP-WEIXIN || MP-QQ
    query
      .select('#canvasId')
      .fields({
        node: true,
        size: true,
        context: true,
      })
      .exec((res) => {
        // #ifndef MP-QQ
        const canvas = res[0].node
        const ctxvb = canvas.getContext('2d')
        const dpr = uni.getSystemInfoSync().pixelRatio
        canvas.width = res[0].width * dpr
        canvas.height = res[0].height * dpr
        ctxvb.scale(dpr, dpr)
        resolve({ ctx2d: ctxvb, canvas: canvas })
        // #endif
        // #ifdef MP-QQ
        resolve({ ctx2d: res[0].context, canvas: null })
        // #endif
      })
    // #endif
  })
}
function drawNvue_init() {
  /*获取元素引用*/
  var ganvas = vnodeCtx.$refs[canvasId.value]
  /*通过元素引用获取canvas对象*/
  var canvasObj = enable(ganvas, {
    bridge: WeexBridge,
  })
  return canvasObj.getContext('2d')
}
function save(): Promise<string> {
  return new Promise((su, fa) => {
    if (!ctx) {
      uni.showToast({ title: '初始化失败', icon: 'none' })
      fa('初始化失败')
      return
    }
    let width = props.width
    let height = props.height
    // #ifdef APP-NVUE
    uni.showLoading({ title: '...' })
    ctx.toTempFilePath(0, 0, width, height, uni.upx2px(width), uni.upx2px(height), 'png', 1, function (res) {
      uni.hideLoading()
      console.log(res.errMsg)
      if (res.errMsg == 'canvasToTempFilePath:ok') {
        su(res.tempFilePath)
      } else {
        fa(res.errMsg)
      }
    })
    // #endif
    // #ifndef APP-NVUE
    uni.canvasToTempFilePath({
      x: 0,
      y: 0,
      width: uni.upx2px(width),
      height: uni.upx2px(height),
      canvasId: canvasId.value,
      canvas: canvas2d,
      success: function (res) {
        // 在H5平台下，tempFilePath 为 base64
        su(res.tempFilePath)
      },
      fail: (res) => {
        fa(res)
      },
    })

    // #endif
  })
}

//保存条码图片。
defineExpose({ save })
</script>

<style></style>
